package ink.metoo.gude.module.security.filter

import ink.metoo.gude.module.security.domain.JwtConst
import ink.metoo.gude.module.security.service.TokenService
import ink.metoo.gude.module.security.util.original
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter

@Component
class JwtAuthenticationFilter(
    private val tokenService: TokenService,
    private val userDetailsService: UserDetailsService
) : OncePerRequestFilter() {

    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        try {
            val header = request.getHeader(JwtConst.AUTHORIZATION_HEADER_NAME)
            if (header != null && header.startsWith(JwtConst.BEARER)) {
                val token = header.substring(JwtConst.BEARER.length)
                val claims = tokenService.getClaims(token) ?: return
                val userDetails = userDetailsService.loadUserByUsername(claims.subject)
                if (!tokenService.isTokenExpired(claims, userDetails.original!!)) {
                    val authentication =
                        UsernamePasswordAuthenticationToken(userDetails, token, userDetails.authorities)
                    SecurityContextHolder.getContext().authentication = authentication
                }
            }
        } finally {
            filterChain.doFilter(request, response)
        }

    }

}